\chapter{Testing}
\label{chap:runtests}

When bigtop builds your application, it makes four test files.  These are
kept up to date on each rebuild, unless you turn them off in some way.  This
chapter explains their purposes and uses, then goes on to explain how to
use one of them as a model for building your own more elaborate tests.

\section{Standard Tests by bigtop}

The Control backends are responsible for building tests to go with their
controllers.  The Control Gantry backend builds and maintains four
test\index{bigtop!default tests}\index{tests!bigtop defaults}
files
in the t subdirectory of the build directory.  They are summarized in
Table \ref{tab:gentests}.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Test Name & Purpose \\
\hline
\verb+01_use.t+      & one \verb+use_ok+ test for each controller stub      \\
\verb+02_pod.t+      & standard Test::Pod \verb+all_pod_files_ok+           \\
\verb+03_podcover.t+ & standard Test::Pod::Coverage                         \\
                     & \verb+all_pod_files_ok+ \\
\verb+10_run.t+      & default page request for each controller             \\
\end{tabular}
\end{center}
\caption{List of bigtop generated tests.}
\label{tab:gentests}
\end{table}

These test files are purposely spartan.  You are not meant to edit them.
Rather, you should augment them with additional files.
To run\index{tests!running} them, build in the usual way:

{\footnotesize
\begin{verbatim}
perl Build.PL
./Build
./Build test
\end{verbatim}
}

Once you do that, you can usually re-run the tests with just the last step.

There is nothing particularly interesting about the \verb+use_ok+ tests,
they merely check compilation of each controller module.  The pod and
pod coverage tests are even less interesting.  To use them, you need to
install Test::Pod and Test::Pod::Coverage and set the \verb+TEST_POD+
environment variable in your shell.

The run tests are slightly more interesting.  There is one test for
each controller in the application, plus one for the base
module.\begin{footnote}You can skip the run tests on a controller
by controller basis.  Either check the \verb+skip_test+ box for the
controller in tentmaker or add a \verb+skip_test+ statement to the
controller's block in your bigtop file with a text editor.\end{footnote}
Each test is a simple page hit
on the \verb+do_main+ method, which only checks for successful return
status.  Yet, these can still serve as an example for your own tests.
So, let's look at them in more detail.

\section{Run Tests}

To explain how to build specific tests, I'll start by walking you through
the tests bigtop makes by default, using
\verb+t/10_run.t+\index{tests!page hits}\index{10 run.t@\verb+10_run.t+}
from the
address book example in Chapter \ref{chap:simpleex} in particular.  I'll
show a little bit of the script at a time with comments interspersed.
To see the whole thing simply look at the \verb+t/10_run.t+ bigtop makes
when you type:

{\footnotesize
\begin{verbatim}
bigtop -n AddressBook address
\end{verbatim}
}

The real version has a bit more in it.  I've distilled it to show what
you need to do for your own tests, avoiding issues like the SKIP block
which prevents default tests from running if you don't have an SQLite
database for them to use.
The top of the script is typical of any test which relies on
Test::More\index{Test::More}:

{\footnotesize
\begin{verbatim}
use strict;

use Test::More tests => 2;

use AddressBook qw{ -Engine=CGI -TemplateEngine=TT };

use Gantry::Server;
use Gantry::Engine::CGI;
\end{verbatim}
}

It uses the base module of the application, specifying the CGI and TT
engines.  Then it brings in Gantry::Server to drive the tests and the
CGI engine\index{CGI!Gantry engine object}.

{\footnotesize
\begin{verbatim}
my $cgi = Gantry::Engine::CGI->new( {
    config => {
        dbconn => 'dbi:SQLite:dbname=app.db',
        template_wrapper => 'genwrapper.tt',
        root => 'html/templates',
    },
    locations => {
        '/' => 'AddressBook',
        '/address' => 'AddressBook::Address',
    },
} );
\end{verbatim}
}

For ease, Bigtop generates CGI based tests.  To follow its plan, we
need a CGI engine object.  The configuration here is minimal,
containing only the database DSN string, Template Toolkit wrapper file name,
and trivial root template path.  Recall that the original address book
had only one table called address.  So, there are two locations here: the
base location and one for the sole table.  The locations hash key
stores URI to controller mappings.  The URIs are absolute from the document
root of the server.

{\footnotesize
\begin{verbatim}
my @tests = qw(
    /
    /address
);
\end{verbatim}
}

The generated test script will hit each location.  When you write your
own tests, there is no need to repeat these hits on each controller's default
URL.  See Section \ref{sec:customtests} below for how to make more
interesting hits.

{\footnotesize
\begin{verbatim}
my $server = Gantry::Server->new();
$server->set_engine_object( $cgi );
\end{verbatim}
}

We need to instantiate a Gantry::Server.  Gantry::Server is a subclass of
HTTP::Server::Simple.  To avoid constructor overloading, Gantry::Server
provides \verb+set_engine_object+.  We pass it the CGI engine object
built earlier.

{\footnotesize
\begin{verbatim}
foreach my $location ( @tests ) {
    my( $status, $page ) =
            $server->handle_request_test( $location );

    ok( $status eq '200',
            "expected 200, received $status for $location" );

    if ( $status ne '200' ) {
        print STDERR $page . "\n\n";
    }
}
\end{verbatim}
}

Gantry::Server provides
\verb+handle_request_test+\index{handle request
test@\verb+handle_request_test+}\index{tests!with stand alone server}
for testing.  It simulates
a single page request in the application and returns the result.  The
default tests only check the return status.  You could scrape the page,
if you so desire.  You could also directly query the database from the
test, to see if a particular hit went as expected.  For that you would need
to provide data to the page.  Keep reading.

There are two ways to feed data to a page.  First, query string
parameter passing works as normal.  Second, some pages expect to process
forms, \verb+handle_request_test+ is ready to help them.  If you begin
the URL path with
`POST:'\index{tests!post spoofing}\index{POST!spoofing in tests},
it takes anything
from the query string and feeds it as if it were in the body of a POST
request.  For example, suppose you have a controller with location
\verb+/search+, which expects a form parameter called searchstr:

{\footnotesize
\begin{verbatim}
my @tests = qw(
    POST:/search?searchstr=keyword
);
\end{verbatim}
}

To understand how to test the rest of the page types, we need to take
a step back and discuss Gantry dispatching.

\section{Gantry Dispatching}

Dispatching\index{dispatching}
is the process of turning a browser requested URI into a method
call.  Gantry has a simple scheme, but there are some subtlies.  

The basic scheme is straightforward.  Whether you deliver the application
with \verb+mod_perl+, CGI, FastCGI, or the stand alone server, you must
specify a list of locations and the controllers which respond to them.  If
the browser requests one of those locations directly, Gantry will call the
\verb+do_main+ method in the associated controller.

What happens when the requested location is not listed exactly as a location
is more interesting.  Work begins with the full URL.  If that matches
a location, we would be in the basic scheme.  So, one at a time path elements
are removed from the tail of the URL, until what remains is a location from
the list.   The web server does this for us.  It then passes the remainder of
the URL to Gantry's handler, which uses the first element as the method name
and the remainder as
parameters\index{URL!parameters}\index{parameters!URL passing}
for that method.  Before calling the method,
Gantry prepends
\verb+do_+\index{do method dispatching}
to the name.  This makes it a bit harder for strange URLs to hit methods
unexpectedly -- since only methods beginning with \verb+do_+ are ever called
by Gantry dispatching -- but mostly serves as clear
documentation of which methods in a controller are externally visible.

Here's an example.  Suppose that someone requests
{\footnotesize
\begin{verbatim}
/address/meth/a/b
\end{verbatim}
}
\noindent
on our example address book.  The web server
looks for the longest location prefix it can find in its location
list.  Here that is \verb+/address+.  It hands the request to the
\verb+handler+ method of the registered module for that location, which is
in AddressBook::Address in our example.  The actual
\verb+handler+ method is inherited from Gantry.pm, which uses
the remainder of the URL to decide what method to
call.  If nothing were left, it would call \verb+do_main+.  In this case,
\verb+meth/a/b+ remains, so it will call
\verb+do_meth+,\begin{footnote}
Legal disclaimer: the name of the sample method in the above discussion
is not meant to be taken in the imperative sense.  Don't use drugs.
\end{footnote}
passing it
\verb+a+ and \verb+b+ as arguments.  Thus, the AddressBook::Address
controller needs this method:

{\footnotesize
\begin{verbatim}
sub do_meth {
    my ( $self, $arg1, $arg2 ) = @_;
    # $arg1 is now 'a' while $args2 is 'b'
    #... respond to request here
}
\end{verbatim}
}

\section{Custom Tests\index{tests!custom}}
\label{sec:customtests}

Now that we understand the dispatching scheme explained in the previous
section, it is a small step to creating tests of arbitrary \verb+do_+
methods with parameters and/or form data.
If the method in question is expecting data from the URL, there is not
much to the test.  Simply add it to the URL in the \verb+@tests+ list.
For example:

{\footnotesize
\begin{verbatim}
my @tests = qw(
    /address/stubby/a/b/c
);
\end{verbatim}
}

For the current app, this will test a hit to the \verb+do_stubby+ subroutine,
which will receive \verb+a+, \verb+b+, and \verb+c+ as parameters.

%If the method expected its parameters in the query string, we could have said:
%
%{\footnotesize
%\begin{verbatim}
%my @tests = qw(
%    /address/stubby?var=val&var2=val2
%);
%\end{verbatim}
%}

The only thing clever is form submission.  As mentioned above, to post
form parameters, just add \verb+POST:+ to the front of the location
and supply the form parameters as if they were a query string.  Then the
\verb+handle_request_test+ method of the Gantry::Server will take the query
string parameters and pass them as if they were POSTed.

\section*{Summary}

Now that you know how to simulate page hits, you can help yourself to the
various Test:: modules on CPAN to complete your custom testing program.
